package design.mode.factory;

/**
 * <p>
 * 工厂方法模式（Factory Method Pattern）又叫作多态性工厂模式，
 * 指定义一个创建对象的接口，但由实现这个接口的类来决定实例化哪个类，
 * 工厂方法把类的实例化推迟到子类中进行。<br/>
 * 原文：Define an interface for creating an object，
 * but let subclassesdecide which class to instantiate.
 * Factory Method lets a class deferinstantiation to subclasses.<br/>
 * 在工厂方法模式中，不再由单一的工厂类生产产品，而是由工厂类的子类实现具体产品的创建。
 * 因此，当增加一个产品时，只需增加一个相应的工厂类的子类，实现生产这种产品，
 * 便可以解决简单工厂生产太多产品导致其内部代码臃肿（switch …case分支过多）的问题，也符合开闭原则。<br/>
 * 工厂方法模式主要适用于以下应用场景。<br/>
 * （1）创建对象需要大量重复的代码。<br/>
 * （2）客户端（应用层）不依赖产品类实例如何被创建、实现等细节。<br/>
 * （3）一个类通过其子类来指定创建哪个对象。<br/>
 * <p/>
 */
public class FactoryMethodPattern {
    /**
     * <br/>
     * 工厂方法模式的优点：<br/>
     * （1）灵活性增强，对于新产品的创建，只需多写一个相应的工厂类。<br/>
     * （2）典型的解耦框架。高层模块只需要知道产品的抽象类，无须关心其他实现类，满足迪米特法则、依赖倒置原则和里氏替换原则。<br/><br/>
     * 工厂方法模式的缺点：<br/>
     * （1）类的个数容易过多，增加复杂度。<br/>
     * （2）增加了系统的抽象性和理解难度。<br/>
     * （3）抽象产品只能生产一种产品，此弊端可使用抽象工厂模式解决。<br/>
     *
     * @param args
     */
    public static void main(String[] args) {
        IFactory factory = new FactoryA();
        factory.makeProduct().doSomething();

        factory = new FactoryB();
        factory.makeProduct().doSomething();

        factory = new FactoryC();
        factory.makeProduct().doSomething();
    }

    /**
     * 抽象工厂（IFactory）：是工厂方法模式的核心，与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
     */
    public interface IFactory{
        IProduct makeProduct();
    }

    /**
     * 生产ProductA的具体工厂
     */
    static class FactoryA implements IFactory{
        @Override
        public IProduct makeProduct() {
            return new ProductA();
        }
    }


    /**
     * 生产ProductB的具体工厂
     */
    static class FactoryB implements IFactory{
        @Override
        public IProduct makeProduct() {
            return new ProductB();
        }
    }

    /**
     * 生产ProductC的具体工厂
     */
    static class FactoryC implements IFactory{
        @Override
        public IProduct makeProduct() {
            return new ProductC();
        }
    }

    /**
     * 抽象产品（IProduct）：是工厂方法模式所创建的对象的超类型，也就是产品对象的共同父类或共同拥有的接口。
     */
    public interface IProduct{
        void doSomething();
    }

    /**
     * 具体产品A
     */
    static class ProductA implements IProduct {
        @Override
        public void doSomething() {
            System.out.println("Product A doSomething");
        }
    }

    /**
     * 具体产品B
     */
    static class ProductB implements IProduct {
        @Override
        public void doSomething() {
            System.out.println("Product B doSomething");
        }
    }

    /**
     * 具体产品C
     */
    static class ProductC implements IProduct {
        @Override
        public void doSomething() {
            System.out.println("Product C doSomething");
        }
    }
}
